﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using DimensionsHelper.Common.Contracts.DataCollector;
using DimensionsHelper.Common.Contracts.DataCollector.Options;
using DimensionsHelper.Common.Contracts.Excel;
using DimensionsHelper.Common.Contracts.Excel.Options;
using DimensionsHelper.Common.Contracts.Services;
using DimensionsHelper.Common.Utils;
using DimensionsHelper.Services.DataCollector.Options;
using DimensionsHelper.Services.Excel;

namespace DimensionsHelper.Services.DataCollector;

public class ExcelSummaryWriter : IExcelSummaryWriter
{
    private static readonly ExcelStyleColor[] InteriorColors =
    [
        ExcelStyleColors.AliceBlue,
        ExcelStyleColors.Orange,
        ExcelStyleColors.LightCoral,
        ExcelStyleColors.LightCyan,
        ExcelStyleColors.LightGreen,
        ExcelStyleColors.LightYellow,
        ExcelStyleColors.LightSalmon,
        ExcelStyleColors.LightSeaGreen,
        ExcelStyleColors.LightSteelBlue,
        ExcelStyleColors.LightSkyBlue,
        ExcelStyleColors.LightPink,
        ExcelStyleColors.LightGoldenrodYellow
    ];

    private static readonly ExcelStyleColor[] ValueAtColors =
    [
        ExcelStyleColors.DarkBlue,
        ExcelStyleColors.DarkOrange,
        ExcelStyleColors.DarkGreen,
        ExcelStyleColors.DarkCyan,
        ExcelStyleColors.DarkRed,
        ExcelStyleColors.DarkOrchid,
        ExcelStyleColors.DarkMagenta,
        ExcelStyleColors.DarkKhaki
    ];

    private readonly Dictionary<string, ColumnGroupInfo> _columnKeyGroups = new();
    private readonly Locator<TableColumn> _columnLocator = new((key, value) => new TableColumn(key, value));

    private readonly List<int> _keyRows = [];
    private readonly List<int> _noValueRows = [];
    private readonly List<ExcelDataNode> _reorderedDataNodes = [];

    private readonly Locator<TableRow> _rowLocator = new((key, value) => new TableRow(key, value, 0));

    // 记录所有类型深度
    private readonly Stack<KeyValuePair<string, string>> _rowPathStack = new();
    private readonly List<KeyValuePair<string, string>> _subgroupNameValues = [];

    private readonly HashSet<string> _subgroupTypes = [];
    private int _aliasColumn;
    private Export? _currentExport;
    private IExcelWorksheetOperator? _currentSheet;


    /**
     * 写入时
     * 1. 对于不包含数据的类型，填写到列关键字 ColumnKey 单元格下方
     * 2. ColumnKey 类型如果绑定了 Test 的Flag，填写到上方
     *
     * +--------------+--------------+
     * |              |ColumnKey Flag|
     * +--------------+--------------+
     * | ValueAt Name |  Column Key  |  ...
     * +--------------+--------------+
     * |              |    Total     |  ...
     * +--------------+--------------+
     * |              |     ...      |  ...
     * +--------------+--------------+
     * |    Type      |   Value      |  ...
     * +--------------+--------------+
     */
    private IExcelWorkbookOperator? _currentWorkbook;


    /**
     * 1. 这个输出格式忽略 Headers 配置。
     * 2. 当 Aggregate 属性不是空时，将配置节点重排到最上层。
     * 3. 将 ColumnKey 节点重拍到最下层。
     */
    private ExcelDataNode? _dataNode;
    private OptionHelper _helper;

    private ExcelDataNode _reorderedRoot = new();

    private int _keyRow = 1;
    private int _row = 1;
    private int _startColumn = 1;
    private int _valueAtIndex;
    private string _valueAtLabel = string.Empty;
    private IReportService? _reportService;
        
        
    private Export CurrentExport => _currentExport!;

    public string Section => "SummaryWriter";

    public ExcelSummaryWriter(IReportService? reportService)
    {
        _reportService = reportService;

        var validator = new Validator
        {
            ReportService = reportService,
        };
        
        _helper = new OptionHelper(new CollectorOptions(), validator);
    }

    public IFilePikerService? FilePikerService
    {
        get; set;
    }
        
    public IReportService? ReportService
    {
        get => _reportService;
        set
        {
            if (_reportService == value)
            {
                return;
            }

            _reportService = value;
            _helper.Validator.ReportService = value;
        }
    }


    public void SetOptions(object option)
    {
        switch (option)
        {
            case OptionHelper optionHelper:
                _helper = optionHelper;
                break;

            case CollectorOptions collectorOptions:
                var validator = new Validator
                {
                    ReportService = ReportService
                };
                _helper = new OptionHelper(collectorOptions, validator);
                break;
        }
    }

    public void WriteToExcel(IExcelWorkbookOperator workbook, object data, CancellationToken cancellationToken)
    {
        if (data is not ExcelDataNode d)
        {
            ReportService?.Error($"数据类型不符，应为'{nameof(ExcelDataNode)}'。");
            return;
        }

        if (_helper.Options.Exports.Count == 0)
        {
            ReportService?.Error("未添加输出配置，程序已退出。");
            return;
        }

        _dataNode = d;

        ReportService?.Log("开始输出工作簿。");

        try
        {
            _currentWorkbook = workbook;

            foreach (var export in _helper.Options.Exports.Values)
            {
                _currentExport = export;

                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }

                ReportService?.Log($"开始输出工作表 - '{export.Name}'");
                _currentSheet = GetWorksheet(export.Name);
                WriteToExcelSheet(cancellationToken);
                ReportService?.Log($"工作表 - '{export.Name}'输出完成。");
            }
        }
#if !DEBUG
            catch (Exception ex)
            {
                ReportService?.Error(ex.Message);
            }
#endif
        finally
        {
            _currentWorkbook?.Save();
            _currentWorkbook?.Close();
            _currentWorkbook = null;
            ReportService?.Log("工作簿输出完成。");
        }
    }


    public void WriteToExcel(IExcelWorkbookOperator workbook, object data)
    {
        WriteToExcel(workbook, data, CancellationToken.None);
    }


    private static string GapColumnKeySelector(Gap gap)
    {
        return $"L{gap.LeftIndex}R{gap.RightIndex}";
    }

    private bool ReorderDataNodePath(List<ExcelDataNodePathElement> path)
    {
        if (path.Count > 0 && !path[path.Count - 1].Type.Equals(_helper.ColumnKeyType.Name))
        {
            var keyIndex = path.FindIndex(e => e.Type.Equals(_helper.ColumnKeyType.Name));
            if (keyIndex > -1)
            {
                var keyElement = path[keyIndex];
                path.RemoveAt(keyIndex);
                path.Add(keyElement);
            }
            else
            {
                return false;
            }
        }

        var index = path.FindIndex(e => e.Type.Equals(CurrentExport.ValueAt));

        if (index == -1)
        {
            return false;
        }

        var element = path[index];
        path.RemoveAt(index);
        path.Insert(0, element);
        return true;
    }


    private void ReorderAndAddDataNode(ExcelDataNode root, ExcelDataNode node,
        Action<List<ExcelDataNodePathElement>>? pathCallback)
    {
        foreach (var childNode in node.GetDataChildren())
        {
            var path = childNode.GetPath();
            pathCallback?.Invoke(path);

            if (!ReorderDataNodePath(path) || _helper.IsFilteredOut(CurrentExport, path))
            {
                continue;
            }

            var reorderedNode = root.GetChild(path);
            reorderedNode.Data.CopyValue(childNode.Data);
            _reorderedDataNodes.Add(reorderedNode);
        }
    }


    private bool ReorderDataNode()
    {
        if (_dataNode == null)
        {
            ReportService?.Error("未添加已读取的数据。");
            return false;
        }

        if (_currentExport == null)
        {
            ReportService?.Error("未添加输出配置。");
            return false;
        }

        if (string.IsNullOrEmpty(_currentExport.ValueAt))
        {
            ReportService?.Error("未配置分类类型。");
            return false;
        }

        _reorderedRoot = new ExcelDataNode();
        _reorderedDataNodes.Clear();

        ReportService?.Log($"开始数据重排，分类类型 - {_currentExport.ValueAt}");

        // 删除掉符合 currentExport.Filter 的节点，并且，
        // 将 currentExport.ValueAt 节点的不同类型兄弟节点移动到其子节点。

        ExcelDataNode.ForEachChild(_dataNode, args =>
        {
            var node = args.Node;

            if (!string.IsNullOrEmpty(_currentExport.ValueAt) && node.Type.Equals(_currentExport.ValueAt))
            {
                ReorderAndAddDataNode(_reorderedRoot, node, null);
                args.IsDfsStopped = true;
            }
            else if (node.Parent != null && node.Parent.CountType(_currentExport.ValueAt) > 0)
            {
                foreach (var valueAt in node.Parent.Filter(_currentExport.ValueAt))
                {
                    ReorderAndAddDataNode(_reorderedRoot, node, path =>
                    {
                        if (path.FindIndex(e => e.Type.Equals(_currentExport.ValueAt)) > -1)
                        {
                            return;
                        }

                        var newElement = new ExcelDataNodePathElement(valueAt);
                        // 插入到当前节点之前
                        var index = path.FindIndex(e => e.Type == node.Type);
                        if (index > -1)
                        {
                            path.Insert(index, newElement);
                        }
                        else
                        {
                            path.Add(newElement);
                        }
                    });
                }

                args.IsDfsStopped = true;
            }
        });

        return true;
    }


    private string GetIndexValue(int index)
    {
        return _currentExport != null ? $"{_currentExport.IndexName}{index}" : index.ToString();
    }


    /// <summary>
    ///     判断当前输出配置中的类型是否包含别名
    /// </summary>
    private bool IsExportTypesContainsAlias()
    {
        if (_currentExport == null)
        {
            return false;
        }

        return _helper.IsTypeContainsAlias(CurrentExport.ValueAt)
               || CurrentExport.Headers.Any(t => _helper.IsTypeContainsAlias(t));
    }


    private void StartSheet()
    {
        _subgroupTypes.Clear();

        _currentSheet = _currentWorkbook!.GetWorksheet(CurrentExport.Name);
        _startColumn = CurrentExport.StartColumn;

        if (_startColumn <= 0)
        {
            _startColumn = 1;
        }

        if (IsExportTypesContainsAlias())
        {
            _aliasColumn = _startColumn;
            _startColumn++;
        }

        _row = CurrentExport.StartRow;

        if (_row <= 0)
        {
            _row = 1;
        }

        _keyRow = _row + 1;

        var headerSet = new HashSet<string>(CurrentExport.Headers);
        foreach (var type in _helper.Options.Types.Settings.Keys)
        {
            if (type == _helper.Options.Types.ColumnKey ||
                type == CurrentExport.ValueAt ||
                headerSet.Contains(type))
            {
                continue;
            }

            _subgroupTypes.Add(type);
            // 将不出示在行上的类型值作为 subgroup 交叉在列上。
            foreach (var subgroup in _helper.GetFinalValues(type))
            {
                _subgroupNameValues.Add(new KeyValuePair<string, string>(type, subgroup));
            }
        }

        _noValueRows.Clear();
        _keyRows.Clear();
        _rowLocator.Clear();
        _columnLocator.Clear();
        _columnKeyGroups.Clear();
        _rowPathStack.Clear();
    }


    private void FormatSheet()
    {
        _currentSheet?.AutoFitEntireColumns();
    }


    private void FinishSheet()
    {
        FormatSheet();
        _currentSheet = null;
        _subgroupTypes.Clear();
        _subgroupNameValues.Clear();
        _rowLocator.Clear();
        _columnLocator.Clear();
        _columnKeyGroups.Clear();
        _rowPathStack.Clear();
    }

    private static List<KeyValuePair<string, string>> BuildPath(params (string Key, string Value)?[] args)
    {
        return (
            from item in args
            where item != null
            select new KeyValuePair<string, string>(item.Value.Key, item.Value.Value)
        ).ToList();
    }


    private static T LocatorGetOrAdd<T>(Locator<T> locator, string key, string value,
        params (string, string)?[] args) where T : class, ILocatable
    {
        var path = BuildPath(args);
        path.Add(new KeyValuePair<string, string>(key, value));

        var find = locator.Find(path);
        if (find != null)
        {
            return find;
        }

        find = locator.Create(key, value);
        foreach (var item in args)
        {
            if (item != null)
            {
                find.AddPath(item.Value.Item1, item.Value.Item2);
            }
        }

        locator.Add(find);
        return find;
    }


    private IExcelRangeOperator GetRange(int row, int col)
    {
        return _currentSheet!.GetRange(row, col);
    }

    /**
     * 初始化行时，对于不同类型的定义，进行嵌套配置。
     * 如果类型不存储值，后续类型嵌套到此类型下。
     * 此时，需要递归创建表格行。
     */
    private void AddTableRow(GroupType typeObj, string value, int row)
    {
        var tableRow = _rowLocator.Create(typeObj.Name, value);
        tableRow.Row = row;
        tableRow.NoValue = typeObj.NoValue;
        tableRow.AddPath(_rowPathStack);
        _rowLocator.Add(tableRow);
    }

    private string? PathTypeValueGetter(string typeName)
    {
        return (
            from item in _rowPathStack where item.Key == typeName select item.Value
        ).FirstOrDefault();
    }

    private void InitTableRows(ref int row, int index, string[] typeNames)
    {
        if (index >= typeNames.Length)
        {
            return;
        }

        var typeName = typeNames[index];

        if (!_helper.TryGetType(typeName, out var typeObj))
        {
            return;
        }

        // 如果行上写入 currentExport.ValueAt，只写入当前值。
        if (typeName == CurrentExport.ValueAt)
        {
            AddTableRow(typeObj, _valueAtLabel, row);
            FillRowHeader(typeName, row, _valueAtLabel, typeObj.NoValue ? RowFlagsNoValue : 0);
            row++;
            InitTableRows(ref row, index + 1, typeNames);
            return;
        }

        var finalValues = _helper.GetFinalValues(typeName);
        // 跳过没有有效值的类型
        if (finalValues.Count == 0)
        {
            InitTableRows(ref row, index + 1, typeNames);
            return;
        }

        /*
         * NoValue1 --+   +--- Value1
         *    |       |   |
         *    |   NoValue2+--- Value2
         *    |       |   |
         *    |      ...  +--- Value3
         *    |
         * NoValue1 ...
         *    |
         *   ...
         */

        foreach (var val in _helper.GetFinalValues(typeName))
        {
            var flag = 0;
            if (typeObj.NoValue)
            {
                flag |= RowFlagsNoValue;
            }

            if (!typeObj.NoValue)
            {
                AddTableRow(typeObj, val, row);
            }

            FillRowHeader(typeName, row, _helper.TryGetTypeValue(typeName, val, PathTypeValueGetter) ?? val, flag);
            row++;

            // 如果是标签值，应当作为嵌套交叉后续的类型定义。
            // 后续定义此时都交给递归函数
            if (typeObj.NoValue)
            {
                _noValueRows.Add(row - 1);
                // 递归
                _rowPathStack.Push(new KeyValuePair<string, string>(typeName, val));
                InitTableRows(ref row, index + 1, typeNames);
                _rowPathStack.Pop();
            }
        }

        // 如果不是标签值，填充后续行
        if (!typeObj.NoValue)
        {
            InitTableRows(ref row, index + 1, typeNames);
        }
    }


    /// <summary>
    ///     初始化表格的行头，表侧应当是 valueAtType 嵌套其他 Headers 的配置。
    /// </summary>
    private void InitSheetRows(GroupType valueAtType)
    {
        _valueAtIndex = 0;
        var valueAtTypeVals = _helper.GetFinalValues(valueAtType.Name);
        foreach (var val in valueAtTypeVals)
        {
            _valueAtLabel = val;

            var r = _keyRow;
            FillRowHeader(valueAtType.Name, r, val.ToUpper(), RowFlagsValueAt);
            _keyRows.Add(r);
            r++;
            _valueAtIndex++;

            // 如果包含Subgroups，向下顺延一行。
            if (_subgroupNameValues.Count > 0)
            {
                r++;
            }

            _rowPathStack.Push(new KeyValuePair<string, string>(valueAtType.Name, val));
            InitTableRows(ref r, 0, CurrentExport.Headers);
            _rowPathStack.Pop();

            _keyRow = r + 1;
        }
    }

    /// <summary>
    ///     将 ColumnKey 类型中的值依据 Testing 中的分组配置进行分组，如果没有分组，将有一个空字符串的为Key的列表。
    /// </summary>
    private void GroupColumnKey()
    {
        _columnKeyGroups.Clear();
        _columnKeyGroups.Add(string.Empty, new ColumnGroupInfo());
        var colors = new List<ExcelStyleColor>(InteriorColors);
        var random = new Random();

        foreach (var val in _helper.GetFinalValues(_helper.ColumnKeyType.Name))
        {
            if (!_helper.TryFindGrouping(_helper.ColumnKeyType.Grouping, val, out var groupNames))
            {
                _columnKeyGroups[string.Empty].Values.Add(val);
            }
            else
            {
                foreach (var groupName in groupNames)
                {
                    if (!_columnKeyGroups.TryGetValue(groupName, out var info))
                    {
                        info = new ColumnGroupInfo { Name = groupName };
                        _columnKeyGroups.Add(groupName, info);
                        // 随机挑选一个颜色
                        if (colors.Count > 0)
                        {
                            var index = random.Next(0, colors.Count - 1);
                            info.Color = colors[index];
                            colors.RemoveAt(index);
                        }
                    }

                    info.Values.Add(val);
                }
            }
        }
    }

    /**
     * 写入列头时，需要首先针对 ColumnKey 使用的分组配置进行列分组，
     * 其次，再根据 Export.Indices 进行分列。
     *
     * +----------+----------+----------+----------+----------+----------+
     * |  Group1  |  Group1  |  Group1  |  Group1  |  Group1  |  Group1  |  ...
     * +----------+----------+----------+----------+----------+----------+
     * |   Key 1  |   Key 1  |   Key 1  |   Key 2  |   Key 2  |   Key 2  |  ...
     * +----------+----------+----------+----------+----------+----------+
     * |  Index 1 |  Index 2 |    ...   |  Index 1 |  Index 2 |    ...   |  ...
     * +----------+----------+----------+----------+----------+----------+
     *
     * Gap 列以同样的拆分格式放在原始值后面。
     */
    private void FillColumnKey(int column, string key, string? subgroup = null)
    {
        foreach (var keyRow in _keyRows)
        {
            FillCell(keyRow, column, key, ColFlagsKey | RowFlagsContent);
            FillCell(keyRow + 1, column, subgroup, RowFlagsContent);
        }
    }

    private void InitSingleKeySubgroupIndexColumns(ref int column, string key, ColumnGroupInfo group,
        (string, string)? subgroup = null)
    {
        var groupName = group.Name;
        // 跳过筛选ColumnKey的Filter
        if (_helper.IsFilteredOut(CurrentExport, _helper.ColumnKeyType.Name, key))
        {
            return;
        }

        (string, string)? columnGroup = null;

        if (!string.IsNullOrEmpty(_helper.ColumnKeyType.Grouping))
        {
            columnGroup = (_helper.ColumnKeyType.Grouping, group.Name);
        }

        var tableColumn =
            LocatorGetOrAdd(_columnLocator, _helper.ColumnKeyType.Name, key, columnGroup, subgroup);
        tableColumn.GapKeySelector = GapColumnKeySelector;
        foreach (var item in CurrentExport.Indices)
        {
            // 填充列关键字分组
            if (!string.IsNullOrEmpty(groupName))
            {
                FillColumnLabel(CurrentExport.StartRow, column, groupName, ColFlagsGroup, group.Color);
            }

            tableColumn.SetIndexColumn(item.Index, column);

            // 填充所有 列关键字
            FillColumnKey(column, key, subgroup?.Item2);

            // 填充所有行 Subgroup
            foreach (var noValRow in _noValueRows)
            {
                FillCell(noValRow, column, GetIndexValue(item.Index), RowFlagsContent | RowFlagsNoValue);
            }

            column++;
        }
    }

    private void InitSingleKeySubgroupGapColumns(ref int column, ColumnGroupInfo group, Gap gapObj,
        (string, string)? subgroup = null)
    {
        foreach (var groupVal in group.Values)
        {
            // 跳过筛选ColumnKey的Filter
            if (_helper.IsFilteredOut(CurrentExport, _helper.ColumnKeyType.Name, groupVal))
            {
                return;
            }

            var tableColumn =
                LocatorGetOrAdd(_columnLocator, _helper.ColumnKeyType.Name, groupVal, subgroup);
            tableColumn.GapKeySelector = GapColumnKeySelector;

            if (!tableColumn.TrySetGapColumn(gapObj, column))
            {
                continue;
            }

            // 填充列关键字分组
            if (!string.IsNullOrEmpty(group.Name))
            {
                FillColumnLabel(CurrentExport.StartRow, column, group.Name, ColFlagsGroup, group.Color);
            }

            // 填充所有 列关键字
            FillColumnKey(column, groupVal, subgroup?.Item2);
            // 填充所有 Gap描述
            FillGapLabel(column, gapObj);
            column++;
        }
    }

    private void InitSingleGroup(ref int column, ColumnGroupInfo group)
    {
        // 跳过筛选掉的分组
        if (!string.IsNullOrEmpty(_helper.ColumnKeyType.Grouping) &&
            _helper.IsGroupFilteredOut(CurrentExport, _helper.ColumnKeyType.Grouping, group.Name))
        {
            return;
        }

        if (_subgroupNameValues.Count > 0)
        {
            // 遍历分组的所有下级分组，初始化数值列
            foreach (var pair in _subgroupNameValues)
            {
                // 跳过筛选掉的次级分组
                if (_helper.IsFilteredOut(CurrentExport, pair.Key, pair.Value))
                {
                    continue;
                }

                foreach (var keyVal in group.Values)
                {
                    FormatKeyColumnRange(column);
                    InitSingleKeySubgroupIndexColumns(ref column, keyVal, group, (pair.Key, pair.Value));
                }

                // 添加一列空白列
                column++;
            }

            // 再次遍历所有下级分组，初始化Gap计算列
            foreach (var gap in CurrentExport.Gaps)
            {
                foreach (var pair in _subgroupNameValues)
                {
                    // 跳过筛选掉的次级分组
                    if (_helper.IsFilteredOut(CurrentExport, pair.Key, pair.Value))
                    {
                        continue;
                    }

                    if (!_helper.TryGetGap(gap, out var gapObj))
                    {
                        continue;
                    }

                    FormatKeyColumnRange(column);
                    InitSingleKeySubgroupGapColumns(ref column, group, gapObj, (pair.Key, pair.Value));
                }

                // 添加一列空白列
                column++;
            }
        }
        else
        {
            foreach (var keyVal in group.Values)
            {
                FormatKeyColumnRange(column);
                InitSingleKeySubgroupIndexColumns(ref column, keyVal, group);
            }

            // 添加一列空白列
            column++;

            foreach (var gap in CurrentExport.Gaps)
            {
                if (!_helper.TryGetGap(gap, out var gapObj))
                {
                    continue;
                }

                FormatKeyColumnRange(column);
                InitSingleKeySubgroupGapColumns(ref column, group, gapObj);
            }

            // 添加一列空白列
            column++;
        }
    }


    private void InitSheetColumns()
    {
        GroupColumnKey();
        var columns = new List<ColumnGroupInfo>();
        // 检查是否使用 Grouping 的定义顺序排序
        if (!string.IsNullOrEmpty(CurrentExport.OrderBy) &&
            _helper.TryGetGroupMemberNames(_helper.ColumnKeyType.Grouping, out var keyGrouping))
        {
            foreach (var name in keyGrouping)
            {
                if (_columnKeyGroups.TryGetValue(name, out var groupInfo))
                {
                    columns.Add(groupInfo);
                }
            }
        }

        if (columns.Count == 0)
        {
            columns = [.._columnKeyGroups.Values];
        }

        var col = _startColumn + 1;
        // 针对每个分组，初始化对应的列。
        foreach (var group in columns)
        {
            InitSingleGroup(ref col, group);
        }
    }


    // 使用 CurrentExport.Headers 定义的行头类型初始化表格行。
    private bool StartTable()
    {
        if (!_helper.TryGetType(CurrentExport.ValueAt, out var typeObj))
        {
            ReportService?.Error($"类型'{CurrentExport.ValueAt}'未定义。");
            return false;
        }

        InitSheetRows(typeObj);
        InitSheetColumns();

        return true;
    }


    private void SplitNodePath(List<ExcelDataNodePathElement> path, out Dictionary<string, string> rowPath,
        out Dictionary<string, string> columnPath)
    {
        rowPath = new Dictionary<string, string>();
        columnPath = new Dictionary<string, string>();

        foreach (var element in path)
        {
            if (_subgroupTypes.Contains(element.Type) || element.Type == _helper.ColumnKeyType.Name)
            {
                columnPath.Add(element.Type, element.Name);
            }
            else
            {
                rowPath.Add(element.Type, element.Name);
            }
        }
    }


    private void WriteDataNodeRowColumn(ExcelDataNode node, TableRow tableRow, TableColumn tableColumn,
        List<ExcelDataNodePathElement> path)
    {
        // 填写 Index 数据
        foreach (var exportIndex in CurrentExport.Indices)
        {
            if (!node.Data.TryGetValue(exportIndex.Index, out var data))
            {
                continue;
            }

            var col = tableColumn.GetIndexColumn(exportIndex.Index);

            if (col == -1)
            {
                continue;
            }

            WriteNodeData(tableRow.Row, col, data);
        }

        // 计算 Gap
        foreach (var gap in CurrentExport.Gaps)
        {
            if (!_helper.TryGetGap(gap, path, out var gapObj))
            {
                continue;
            }

            var gapCol = tableColumn.GetGapColumn(gapObj);

            if (gapCol == -1)
            {
                continue;
            }

            if (!node.Data.TryGetValue(gapObj.LeftIndex, out var leftData) ||
                !node.Data.TryGetValue(gapObj.RightIndex, out var rightData))
            {
                continue;
            }

            var gapCell = GetRange(tableRow.Row, gapCol);
            gapCell.Value = leftData - rightData;
            gapCell.NumberFormatLocal = leftData.NumberFormat;
            gapCell.SetStyle(new RangeStyleOptions
            {
                HAlign = ExcelHAlign.Center
            });
        }
    }


    // 此时 node 的 Type 应当是 ColumnKey
    private void WriteDataNode(ExcelDataNode node)
    {
        var path = node.GetPath();
        SplitNodePath(path, out var rowPath, out var columnPath);

        var cols = new List<TableColumn>();
        var tableRow = _rowLocator.Find(rowPath);

        // 跳过未找到行输出类型的节点。
        if (tableRow == null)
        {
            return;
        }

        TableColumn? tableCol;
        // 添加列分组
        if (columnPath.TryGetValue(_helper.ColumnKeyType.Name, out var keyName) &&
            !string.IsNullOrEmpty(_helper.ColumnKeyType.Grouping) &&
            _helper.TryFindGrouping(_helper.ColumnKeyType.Grouping, keyName, out var memberNames))
        {
            foreach (var member in memberNames)
            {
                var colPath = new Dictionary<string, string>(columnPath);
                colPath.TryAdd(_helper.ColumnKeyType.Grouping, member);
                tableCol = _columnLocator.Find(colPath);

                if (tableCol == null)
                {
                    continue;
                }

                cols.Add(tableCol);
            }
        }
        else
        {
            tableCol = _columnLocator.Find(columnPath);

            // 跳过未找到行输出类型的节点。
            if (tableCol == null)
            {
                return;
            }

            cols.Add(tableCol);
        }

        // 跳过未找到行输出类型的节点。
        if (cols.Count == 0)
        {
            return;
        }

        foreach (var col in cols)
        {
            WriteDataNodeRowColumn(node, tableRow, col, path);
        }
    }

    private IExcelWorksheetOperator GetWorksheet(string sheetName)
    {
        IExcelWorksheetOperator sheet;

        if (_currentWorkbook!.Worksheets.Count == 1 && _currentWorkbook.Worksheets[0].Name == "Sheet1")
        {
            sheet = _currentWorkbook.Worksheets[0];
        }
        else
        {
            sheet = _currentWorkbook.GetWorksheet(sheetName);
        }

        return sheet;
    }


    private void WriteToExcelSheet(CancellationToken cancellationToken)
    {
        StartSheet();

        if (!StartTable() || !ReorderDataNode())
        {
            return;
        }

        double count = 1;
        double totalSize = _reorderedDataNodes.Count;

        foreach (var node in _reorderedDataNodes)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }

            WriteDataNode(node);
            ReportService?.Progress(count / totalSize * 100, "开始填充数据 ...");
            count++;
        }

        ReportService?.Log("数据填充完成。");

        _reorderedDataNodes.Clear();
        FinishSheet();
    }

    /*
     * 输出行类型时，允许出现嵌套类型，结构类似一个树形结构。
     *                         +------+------+
     * Type1 -+--------------- | Text | Text | ...
     *        |                +------+------+
     *      Type2 -+---------- | Text | Text | ...
     *             |           +------+------+
     *        Type3 Value1 --- | Data | Data | ...
     *             |           +------+------+
     *        Type3 Value2 --- | Data | Data | ...
     *             |           +------+------+
     *            ...            ...    ...
     *
     *
     * 发生交叉时，同一个值会在同一列上出现多次，需要使用完整的树节点路径
     * 才可以确定唯一的行号。
     *
     */

    private class ColumnGroupInfo
    {
        public string Name { get; set; } = string.Empty;

        public List<string> Values { get; } = [];

        public ExcelStyleColor Color { get; set; } = ExcelStyleColor.Empty;
    }


    #region Fill Excel Cells

    private void WriteNodeData(int row, int col, ExcelDataValue val)
    {
        if (val.Data == null)
        {
            return;
        }

        var cell = GetRange(row, col);
        cell.Value = val.Data;
        cell.FontColor = val.Color;
        cell.NumberFormatLocal = val.NumberFormat;
        cell.SetStyle(new RangeStyleOptions
        {
            HAlign = ExcelHAlign.Center
        });
    }

    private static readonly ExcelStyleColor ColorColumnKey = ExcelStyleColors.Gray;
    private static readonly ExcelStyleColor ColorNoValue = ExcelStyleColors.LightGray;

    private const int RowFlagsValueAt = 0x1;
    private const int RowFlagsNoValue = 0x2;
    private const int RowFlagsContent = 0x4;
    private const int ColFlagsKey = 0x10;
    private const int ColFlagsGroup = 0x20;

    private IExcelRangeOperator FillCell(int row, int column, string? text, int flag)
    {
        var cell = GetRange(row, column);
        if (string.IsNullOrEmpty(text))
        {
            return cell;
        }

        cell.Value = text!;

        var styleOptions = new RangeStyleOptions();

        if ((flag & RowFlagsNoValue) != 0)
        {
            styleOptions.InteriorColor = ColorNoValue;
            styleOptions.Font.FontType = FontType.Bold;
        }

        if ((flag & RowFlagsValueAt) != 0)
        {
            styleOptions.InteriorColor = ValueAtColors[_valueAtIndex % ValueAtColors.Length];
            styleOptions.Font.FontType = FontType.Bold;
            styleOptions.Font.FontColor = ExcelStyleColor.Empty;
            styleOptions.Font.FontSize = 14;
        }

        if ((flag & RowFlagsContent) != 0)
        {
            styleOptions.HAlign = ExcelHAlign.Center;
        }

        if ((flag & ColFlagsKey) != 0)
        {
            styleOptions.InteriorColor = ColorColumnKey;
            styleOptions.HAlign = ExcelHAlign.Center;
            styleOptions.Font.FontColor = ExcelStyleColor.Empty;
            styleOptions.Font.FontType = FontType.Bold;
        }

        if ((flag & ColFlagsGroup) != 0)
        {
            styleOptions.HAlign = ExcelHAlign.Center;
            styleOptions.Font.FontType = FontType.Bold;
        }

        cell.SetStyle(styleOptions);

        return cell;
    }


    private void FillRowHeader(string typeName, int row, string text, int flag)
    {
        FillCell(row, _startColumn, text, flag);

        if (_aliasColumn > 0 && _helper.TryGetAliasByReplacement(typeName, text, out var alias))
        {
            FillCell(row, _aliasColumn, alias, flag);
        }
    }


    private void FillColumnLabel(int row, int column, string text, int flag, ExcelStyleColor? interior = null)
    {
        if (!string.IsNullOrEmpty(text))
        {
            var cell = FillCell(row, column, text, flag);

            if (interior != null)
            {
                cell.SetStyle(new RangeStyleOptions
                {
                    HAlign = ExcelHAlign.Center,
                    InteriorColor = interior
                });
            }
        }
    }


    private void FillGapLabel(int column, Gap gapObj)
    {
        var text = $"{GetIndexValue(gapObj.LeftIndex)}VS{GetIndexValue(gapObj.RightIndex)}";
        foreach (var row in _noValueRows)
        {
            FillCell(row, column, text, RowFlagsContent | RowFlagsNoValue);
        }
    }


    private void FormatKeyColumnRange(int column)
    {
        var range = _currentSheet!.GetRange(1, column, _currentSheet.EndRow, column);
        range.SetStyle(new RangeStyleOptions
        {
            BorderPosition = BorderPosition.Left,
            BorderStyle = BorderStyle.Thin
        });
    }

    #endregion
}